<?php

namespace App\Plugins\Wechat;

use App\Models\Customer;
use Illuminate\Support\Facades\Redis;
use MongoDB\BSON\Regex;

class Messages
{
    protected $_uin;
    protected $_error = '';
    /**
     * @var \MongoDB\Collection $_db
     */
    protected $_db;

    protected $_message;

    public function __construct($uinOrMessage)
    {
        if (is_array($uinOrMessage)) {
            $this->_initByMessage($uinOrMessage);
        } else if (is_numeric($uinOrMessage)) {
            $this->_initByUin($uinOrMessage);
        } else {
            $this->_error = 'init data fault!';
        }
    }

    protected function _initByUin($uin)
    {
        $this->_uin = intval($uin);
        $this->_db = DB::createDb($uin);
    }

    protected function _initByMessage(Array $message)
    {
        $this->_uin = array_get($message, 'clientUin', null);
        if (is_null($this->_uin)) {
            $this->_error = 'not valid uin';
            return;
        }
        $this->_message = $message;
    }

    public function setMessage($message)
    {
        $this->_message = $message;
    }

    /**
     * <title>countNewMessage</title>
     * 统计指定uin客户端的未读消息
     * @param int $preReadTime 上次读取消息的时间
     * @return int
     */
    public function countNewMessage($preReadTime)
    {
        $filter = [
            'uin' => strval($this->_uin),
            'createTime' => ['$gt' => intval($preReadTime)],
        ];
        $count = $this->_db->count($filter);
        return $count;
    }

    /**
     * 聊天历史记录
     * @param $filters 搜索条件
     * @param $limit 分页开始数
     * @param $skip 分页结束数
     * @return array
     */
    public function getMessages($filters, $limit, $skip)
    {
        //查询条件
        $filters = array_merge(['clientUin' => strval($this->_uin)], $filters);
        //总条数
        $total = $this->_db->count($filters);
        //消息列表
        $list = $this->_db->find($filters, [
            'sort' => ['createTime' => -1],
            'limit' => $limit,
            'skip' => $skip,
            'projection' => ['__v' => 0]])->toArray();

        //强转ID
        foreach ($list as $key => $value) {
            $list[$key]->_id = (string)$value->_id;
        }
        return compact('total', 'list');
    }

    /**
     * 读取消息
     * @param $preReadTime
     * @return \stdClass|array
     */
    public function messages($preReadTime)
    {
        $filter = [
            'clientUin' => strval($this->_uin),
            'type' => ['$in' => SETTING::MAP_NORMAL_MSG],
            'to' => ['$exists' => false],
        ];
        if ($preReadTime) {
            $filter['createTime'] = ['$gt' => intval($preReadTime)];
            $r = $this->_db->find($filter, ['projection' => ['__v' => 0]])->toArray();
        } else {
            $r = $this->_db->find($filter, ['sort' => ['createTime' => -1], 'limit' => 10, 'projection' => ['__v' => 0]])->toArray();
        }
        foreach ($r as $item) {
            if ($item->type === SETTING::VERIFY_MSG) {
                $result = new \stdClass();
                $findCustomer = Customer::findByAccount($item->from)->first();
                if ($findCustomer) {
                    $contact = $findCustomer->contactInfo();
                    if (!is_null($contact))
                        $contact['createTime'] = $item->createTime;
                    $result->contact = $contact;
                    $result->type = $item->type;
                }
            } else {
                $result = $item;
                unset($result->_id);
            }
            yield $result;
        }
    }

    /**
     * 发送消息
     * @param null $_message
     * @return int
     */
    public function send($_message = null)
    {
        if (!empty($this->_error)) return 0;
        $clientUin = $this->_uin;
        $message = $_message ?? $this->_message;
        $count = 0;
        if ($clientUin == $message['clientUin']) {
            $type = $message['type'];
            $channelName = sprintf(SETTING::COMMAND_QUEUE, strval($clientUin), SETTING::ACTION_MAP[$type]);
            $count = Redis::publish($channelName, json_encode($message));
        }
        return $count;
    }


    public function saveMessage($messageData)
    {
        $this->_db->insertOne($messageData);
    }

    public function getError()
    {
        return $this->_error;
    }
}